package com.googlecode.grs.robot;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.StringTokenizer;

import com.googlecode.grs.environment.SimulationEnvironment;

/**
 * Creates a robot based on information given from configuration files
 * 
 * @author ajc
 * 
 */
public class RobotFactory {

	/**
	 * Constructs a DrawnRobot that draws a DifferentialDrivenRobot
	 * 
	 * @param env
	 * @param configFile
	 * @return
	 */
	public static DrawnRobot getDrawnDifferential(SimulationEnvironment env,
			String configFile) {

		DifferentialDrivenBot robot = RobotFactory.tryDifferentialBot(env,
				"maps/Example.maze");
		robot.startIntegration();

		env.addRobot(robot);

		SimplePather leftPather = new SimplePather(robot.getLeftWheel());
		SimplePather rightPather = new SimplePather(robot.getRightWheel());
		leftPather.start();
		rightPather.start();

		DrawnRobot drawnRobot = new DrawnRobot(robot);
		drawnRobot.addRobotComponent(leftPather);
		drawnRobot.addRobotComponent(rightPather);
		drawnRobot.addRobotComponent(robot.getLeftWheel());
		drawnRobot.addRobotComponent(robot.getRightWheel());
		return drawnRobot;

	}

	// TODO sort out how to cleanly implement this for various bots

	/**
	 * 
	 * @return a default robot position
	 */
	public static SimpleEventMoveRobot getDefaultSimple(
			SimulationEnvironment env) {
		return new SimpleEventMoveRobot(env, 100, 100, 0);
	}

	/**
	 * 
	 * @return a default robot position
	 */
	public static DifferentialDrivenBot getDefaultDifferential(
			SimulationEnvironment env) {
		return new DifferentialDrivenBot(env, 100, 100, 0);
	}

	/**
	 * Reads a SimulatorEnvironmentFactory configuration file to construct a
	 * ComplexRobot at a certain position, gets a default robot position on file
	 * read failure
	 * 
	 * @param string
	 *            filename of configuration file
	 * @return new ComplexRobot with established position and heading
	 * @throws IOException
	 * @throws NumberFormatException
	 */
	public static DifferentialDrivenBot tryDifferentialBot(
			SimulationEnvironment env, String simEnvString) {
		DifferentialDrivenBot retu = null;
		final int MAX_NUM_ATTEMPTS = 5;
		int numAttempts = 0;
		while (retu == null && numAttempts++ < MAX_NUM_ATTEMPTS) {
			try {
				retu = loadStartPositionToDifferential(env, simEnvString);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				retu = null;
				e.printStackTrace();
			}
		}

		if (retu == null) {
			retu = getDefaultDifferential(env);
		}

		return retu;
	}

	/**
	 * Reads a SimulatorEnvironmentFactory configuration file to construct a
	 * ComplexRobot at a certain position.
	 * 
	 * @param string
	 *            filename of configuration file
	 * @return new ComplexRobot with established position and heading
	 * @throws IOException
	 * @throws NumberFormatException
	 */
	public static DifferentialDrivenBot loadStartPositionToDifferential(
			SimulationEnvironment env, String simEnvConfig)
			throws NumberFormatException, IOException {
		BufferedReader in = new BufferedReader(new FileReader(simEnvConfig));
		String line = "";
		while ((line = in.readLine()) != null) {
			StringTokenizer st = new StringTokenizer(line, ",");
			if (st.countTokens() > 1) {
				String type = st.nextToken();
				if (type.equals("Start")) {
					double xstart = Double.parseDouble(st.nextToken());
					double ystart = Double.parseDouble(st.nextToken());
					if (st.hasMoreTokens()) {
						double orientation = Double.parseDouble(st.nextToken());
						// env.setPosition(xstart, ystart, orientation);
						return new DifferentialDrivenBot(env, xstart, ystart,
								orientation);
					} else
						return new DifferentialDrivenBot(env, xstart, ystart,
								0.0);
				}
			}

		}
		return null;
	}

	/**
	 * Reads a SimulatorEnvironmentFactory configuration file to construct a
	 * ComplexRobot at a certain position, gets a default robot position on file
	 * read failure
	 * 
	 * @param string
	 *            filename of configuration file
	 * @return new ComplexRobot with established position and heading
	 * @throws IOException
	 * @throws NumberFormatException
	 */
	public static SimpleEventMoveRobot trySimple(SimulationEnvironment env,
			String simEnvString) {
		SimpleEventMoveRobot retu = null;
		final int MAX_NUM_ATTEMPTS = 5;
		int numAttempts = 0;
		while (retu == null && numAttempts++ < MAX_NUM_ATTEMPTS) {
			try {
				retu = loadStartPositionToSimple(env, simEnvString);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				retu = null;
				e.printStackTrace();
			}
		}

		if (retu == null) {
			retu = getDefaultSimple(env);
		}

		return retu;
	}

	/**
	 * Reads a SimulatorEnvironmentFactory configuration file to construct a
	 * ComplexRobot at a certain position.
	 * 
	 * @param string
	 *            filename of configuration file
	 * @return new ComplexRobot with established position and heading
	 * @throws IOException
	 * @throws NumberFormatException
	 */
	public static SimpleEventMoveRobot loadStartPositionToSimple(
			SimulationEnvironment env, String simEnvConfig)
			throws NumberFormatException, IOException {
		BufferedReader in = new BufferedReader(new FileReader(simEnvConfig));
		String line = "";
		while ((line = in.readLine()) != null) {
			StringTokenizer st = new StringTokenizer(line, ",");
			if (st.countTokens() > 1) {
				String type = st.nextToken();
				if (type.equals("Start")) {
					double xstart = Double.parseDouble(st.nextToken());
					double ystart = Double.parseDouble(st.nextToken());
					if (st.hasMoreTokens()) {
						double orientation = Double.parseDouble(st.nextToken());
						// env.setPosition(xstart, ystart, orientation);
						return new SimpleEventMoveRobot(env, xstart, ystart,
								orientation);
					} else
						return new SimpleEventMoveRobot(env, xstart, ystart,
								0.0);
				}
			}

		}
		return null;
	}

}
